import { Form, Input, Image, Button, Modal, InputNumber } from 'antd'
import React, { useCallback, useLayoutEffect, useRef, useState, ReactNode, useEffect, useMemo } from 'react'
import { RuleKeys, defaultRules, validateFormItem } from '../utils/validator'
import { inputIds, outputIds } from '../form-container/constants'
import useFormItemInputs from '../form-container/models/FormItem'
import { debounceValidateTrigger } from '../form-container/models/validate'
import { onChange as onChangeForFc } from '../form-container/models/onChange'
import * as Icons from '@ant-design/icons'
import css from './runtime.less'
import { InputIds, ValidateTriggerType } from '../types'
import Tianditu from '../../components/tianditu/tianditu'
import Dialog from '../../components/dialog/dialog'
export interface Lnglat {
  lng: number
  lat: number
  height?: number
  thickness?: number
}

const isLnglat = (v: unknown): v is Lnglat => {
  return typeof v == 'object' && !!v && 'lng' in v && 'lat' in v
}

const isLnglatList = (v: unknown): v is Lnglat[] => {
  return Array.isArray(v) && v.length > 0 && 'lng' in v[0] && 'lat' in v[0]
}
export interface Data {
  value: string | undefined
  rules: any[]
  validateTrigger: string[]
  isTrim: boolean
  lnglat?: [number, number]
  config: {
    allowClear: boolean
    disabled: boolean
    addonBefore: string
    addonAfter: string
    showCount: boolean
    maxLength?: number
    size?: 'large' | 'middle' | 'small'
    placeholder?: string
  }
  src: false | 'inner' | 'custom'
  innerIcon: string
  customIcon: string

  isEditable: boolean
}
function RowEditor(props: { lnglat: Lnglat; onChange?: (value: Lnglat) => void; config: any }) {
  return (
    <tr>
      <td>
        <InputNumber
          style={{ width: '100%' }}
          value={props.lnglat.lng}
          className={css.input}
          type="number"
          {...props.config}
          placeholder="经度"
          onChange={(evt) => {
            props.onChange?.({ ...props.lnglat, lng: evt as number })
          }}
        />
      </td>
      <td>
        <InputNumber
          value={props.lnglat.lat}
          style={{ width: '100%' }}
          className={css.input}
          type="number"
          {...props.config}
          placeholder="纬度"
          onChange={(evt) => {
            props.onChange?.({ ...props.lnglat, lat: evt as number })
          }}
        />
      </td>
      <td>
        <InputNumber
          value={props.lnglat.height || ''}
          className={css.input}
          type="number"
          style={{ width: '100%' }}
          {...props.config}
          placeholder="高度"
          onChange={(evt) => {
            props.onChange?.({ ...props.lnglat, height: evt as number })
          }}
        />
      </td>
      <td>
        <InputNumber
          value={props.lnglat.thickness}
          className={css.input}
          style={{ width: '100%' }}
          type="number"
          {...props.config}
          placeholder="厚度"
          onChange={(evt) => {
            props.onChange?.({ ...props.lnglat, thickness: evt as number })
          }}
        />
      </td>
    </tr>
  )
}
export default function (props: RuntimeParams<Data>) {
  const { env, data, _inputs, inputs, _outputs, outputs, parentSlot, style } = props
  const [openMap, setOpenMap] = useState(false)
  const validateRelOutputRef = useRef<any>(null)
  const [value, setValue] = useState<Lnglat[] | string>([])
  const [realValue, setRealValue] = useState<Lnglat | Lnglat[] | null>(null)
  const [error, setError] = useState('')
  const valueRef = useRef<any>()
  const valueObj = useMemo<Lnglat[] | undefined>(() => {
    if (typeof value == 'string') {
      try {
        return JSON.parse(value)
      } catch {
        return []
      }
    }
    return value || []
  }, [value])

  useFormItemInputs(
    {
      id: props.id,
      name: props.name,
      parentSlot,
      inputs,
      outputs,
      configs: {
        setValue(val) {
          changeValue(val)
        },
        setInitialValue(val) {
          changeValue(val)
        },
        returnValue(output) {
          output(valueRef.current)
        },
        resetValue() {
          changeValue(void 0)
        },
        setDisabled() {
          data.config.disabled = true
        },
        setEnabled() {
          data.config.disabled = false
        },
        setIsEnabled(val) {
          if (val === true) {
            data.config.disabled = false
          } else if (val === false) {
            data.config.disabled = true
          }
        },
        setIsEditable(val) {
          data.isEditable = val
        },
        validate(model, relOutput) {
          validateFormItem({
            value: valueRef.current,
            env,
            model,
            rules: data.rules
          })
            .then((r) => {
              const customRule = (data.rules || defaultRules).find((i) => i.key === RuleKeys.CUSTOM_EVENT)
              if (customRule?.status) {
                validateRelOutputRef.current = relOutput
                outputs[outputIds.ON_VALIDATE](valueRef.current)
              } else {
                relOutput(r)
              }
            })
            .catch((e) => {
              relOutput(e)
            })
        }
      }
    },
    [value]
  )

  useLayoutEffect(() => {
    inputs[inputIds.SET_VALIDATE_INFO]?.((info: object, relOutputs) => {
      if (validateRelOutputRef.current) {
        validateRelOutputRef.current(info)
        relOutputs['setValidateInfoDone'](info)
      }
    })
  }, [])

  const onValidateTrigger = (type: string) => {
    data.validateTrigger?.includes(type) && debounceValidateTrigger(parentSlot, { id: props.id, name: props.name })
  }

  const changeValue = useCallback((val) => {
    setValue(val)
    valueRef.current = val
    onChangeForFc(parentSlot, { id: props.id, name: props.name, value: val })
  }, [])

  const onChange = useCallback((e) => {
    changeValue(e)
    outputs['onChange'](e)
    onValidateTrigger(ValidateTriggerType.OnChange)
  }, [])

  let jsx = (
    <div className={css['edit-table']}>
      <table style={{ width: '100%' }}>
        <thead>
          <tr>
            <th>经度</th>
            <th>纬度</th>
            <th>高度</th>
            <th>厚度</th>
          </tr>
        </thead>
        <tbody>
          {isLnglatList(valueObj)
            ? valueObj.map((lnglat, idx) => (
                <RowEditor
                  key={String(idx + 1)}
                  config={data.config}
                  lnglat={lnglat}
                  onChange={(evt) => {
                    onChange(valueObj.map((item, i) => (i == idx ? evt : item)))
                  }}
                />
              ))
            : null}
          <tr>
            <td colSpan={5} align="right">
              <Button
                type="default"
                style={{ marginTop: 5, marginBottom: 5 }}
                size={data.config.size || 'small'}
                onClick={() => {
                  setError('')
                  setRealValue(null)
                  setOpenMap(true)
                }}
              >
                选取
              </Button>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  )

  return (
    <>
      <div className={css.fiText}>{jsx}</div>
      <Dialog
        open={openMap}
        onOk={() => {
          if (!realValue) {
            setError('请选中坐标或多边形')
            return
          }
          if (isLnglat(realValue)) {
            onChange([realValue])
          } else if (isLnglatList(realValue)) {
            onChange(realValue)
          }
          setOpenMap(false)
        }}
        onClose={() => {
          setOpenMap(false)
        }}
      >
        <Tianditu
          lnglat={data.lnglat}
          width="100%"
          height="calc(100% - 40px)"
          onPositionPick={(evt) => {
            setError('')
            setRealValue(evt)
          }}
          onPolygonPick={(evt) => {
            setError('')
            setRealValue(evt)
          }}
        />
        <div className={css['info']}>{error ? <div style={{ color: 'red' }}>{error}</div> : realValue ? <div>已选择：{JSON.stringify(realValue)}</div> : null}</div>
      </Dialog>
    </>
  )
}
